package com.csii.security.authentication;

import com.alibaba.fastjson.JSON;
import com.csii.base.result.Result;
import com.csii.security.properites.LoginResponseType;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 认证成功处理器
 * 1. 决定 响应json还是跳转页面，或者认证成功后进行其他处理
 * @Auther: ian
 */
@Component("resultTokenAuthenticationSuccessHandler")
public class GeneralAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired(required = false) // 容器中可以不需要有接口的实现，如果有则自动注入
    AuthenticationSuccessListener authenticationSuccessListener;

    @Autowired
    @Lazy
    private ClientDetailsService clientDetailsService;

    @Autowired
    @Lazy
    private AuthorizationServerTokenServices authorizationServerTokenServices;

    @Value("${authorization.clientId:'local9001'}")
    private String clientId;

    private String loginResponseType = "loginResponseType";

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
        HttpServletResponse response, Authentication authentication) throws IOException, ServletException {

        if(authenticationSuccessListener != null) {
            // 当认证之后 ，调用此监听，进行后续处理，比如加载用户权限菜单
            authenticationSuccessListener.successListener(request, response, authentication);
        }
        if(LoginResponseType.REDIRECT.name().equals(request.getAttribute(loginResponseType))) {
            //重定向到上次请求的地址上，引发跳转到认证页面的地址
            logger.info("authentication: " + JSON.toJSONString(authentication));
            super.onAuthenticationSuccess(request, response, authentication);
        }else{
            //2.通过ClientId拿到ClientDetails
            ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
            if(clientDetails == null){
                throw new UnapprovedClientAuthenticationException("clientId对应的配置信息不存在：" + clientId);
            }
            //3.创建TokenRequest
            TokenRequest tokenRequest = new TokenRequest(MapUtils.EMPTY_MAP,clientId,clientDetails.getScope(),"result_token");

            //4.构建OAuth2Request
            OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);

            //5.构建OAuth2Authentication
            OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request,authentication);

            //6.构建OAuth2AccessToken
            OAuth2AccessToken token = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);

            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("userInfo",build(token.getAdditionalInformation()));
            resultMap.put("token",token.getValue());
            //7.将生成的Token返回给请求
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(JSON.toJSONString(Result.ok(resultMap)));
        }
    }


    private Map build(Map<String, Object> principal) {
        Map<String,String> resultMap = new HashMap<>();
        resultMap.put("id",getString(principal.get("userId")));
        resultMap.put("email",getString(principal.get("mail")));
        resultMap.put("avatar",getString(principal.get("avatar")));
        resultMap.put("userName",getString(principal.get("userName")));
        resultMap.put("phone",getString(principal.get("phone")));
        resultMap.put("realname",getString(principal.get("nickName")));
        resultMap.put("openId",getString(principal.get("openId")));
        resultMap.put("openType",getString(principal.get("openType")));
        resultMap.put("relTenantIds",getString(principal.get("tenantId")));
        String userIdentity = getString(principal.get("userIdentity"));
        if (userIdentity != null){
            resultMap.put("userIdentity",userIdentity);
        }
        resultMap.put("departIds",getString(principal.get("departIds")));
        resultMap.put("isSuperAdmin",getString(principal.get("isSuperAdmin")));
        resultMap.put("orgCode",getString(principal.get("orgCode")));
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        resultMap.put("createTime",simpleDateFormat.format(new Date(Long.parseLong(getString(principal.get("createTime"))))));
        return resultMap;
    }





    private String getString(Object obj){
        return obj != null ? obj.toString():null;
    }
}
